package com.zhisheng.core.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

public class CollectionUtils {
	private CollectionUtils() {}

	/**
	 * If the listNum < 1, set the listNum = 1.
	 * @param c
	 * @param listNum how many lists after the given list be splited.
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <E> List<List<E>> splitListByNumber(List<E> c, int listNum) {
		if (c == null || c.size() == 0) {
			return Collections.EMPTY_LIST;
		} else if (listNum < 1) {
			List<List<E>> arr = new ArrayList<List<E>>();
			arr.add(c);
			return arr;
		} 
		
		List<List<E>> list = new ArrayList<List<E>>();
		if (c.size() < listNum) {
			list.add(c);
			return list;
		} else {
			int numberPerSet = c.size() / listNum;
			for (int m = 0; m < listNum; m++) {
				list.add(new ArrayList<E>((int)(numberPerSet * 1.5)));
			}
			
			int k = 0;
			int j = 1;
			for(Iterator<E> it = c.iterator(); it.hasNext(); k++) {
				list.get(j-1).add(it.next());
				if (k > 0 && (k + 1) % numberPerSet == 0 && (k + 1) < listNum * numberPerSet) {
					++j;
				}
			}
			
			return list;
		}
	}
	
	public static <E> List<List<E>> splitListBySize(List<E> c, int listSize) {
		if (c == null || c.size() == 0) {
			return Collections.emptyList();
		} else if (listSize < 1) {
			List<List<E>> arr = new ArrayList<List<E>>();
			arr.add(c);
			return arr;
		} 
		
		int n = 1;
		List<List<E>> returnList = new ArrayList<List<E>>();
		List<E> list = new ArrayList<E>(listSize);
		
		for (int k = 0; k < c.size(); k++) {
			list.add(c.get(k));
			if (n % listSize == 0) {
				List<E> tempList = list;
				list = null;
				returnList.add(tempList);
				list = new ArrayList<E>(listSize);
			}
			++n;
		}
		
		if (c.size() % listSize != 0) {
			returnList.add(list);
		}
		
		return returnList;
	}
	
	public static <T> boolean isEmpty(Collection<T> c) {
		return c == null || c.isEmpty();
	}

	/**
	 * Split one big set to small set.<br>
	 * If the number < 1, set the number = 1.
	 * @param c
	 * @param number
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <E> List<Set<E>> splitSetByNumber(Set<E> c, int number) {
		if (c == null || c.size() == 0) {
			return Collections.EMPTY_LIST;
		} else if (number < 1) {
			List<Set<E>> arr = new ArrayList<Set<E>>();
			arr.add(c);
			return arr;
		} 
		
		List<Set<E>> list = new ArrayList<Set<E>>();
		if (c.size() < 20) {
			list.add(c);
			return list;
		} else {
			int numberPerSet = c.size() / number;
			for (int m = 0; m < number; m++) {
				list.add(new HashSet<E>((int)(numberPerSet * 1.5)));
			}
			
			int k = 0;
			int j = 1;
			for(Iterator<E> it = c.iterator(); it.hasNext(); k++) {
				list.get(j-1).add(it.next());
				if (k > 0 && (k + 1) % numberPerSet == 0 && (k + 1) < number * numberPerSet) {
					++j;
				}
			}
			
			return list;
		}
	}
	
	/**
	 * Split one big set to small set.<br>
	 * If the number < 1, set the number = 1.
	 * @param c
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <E> List<Set<E>> splitSetBySize(Set<E> c, int size) {
		if (c == null || c.size() == 0) {
			return Collections.EMPTY_LIST;
		} else if (size < 1) {
			List<Set<E>> arr = new ArrayList<Set<E>>();
			arr.add(c);
			return arr;
		} 
		
		int n = 1;
		List returnList = new ArrayList();
		Set<E> set = new HashSet<E>(size);
		
		for (E e : c) {
			set.add(e);
			if (n % size == 0) {
				Set<E> tempSet = set;
				set = null;
				returnList.add(tempSet);
				set = new HashSet<E>(size);
			}
			++n;
		}
		
		if (c.size() % size != 0) {
			returnList.add(set);
		}
		
		return returnList;
	}

	/**
	 * Split one big set to small set.<br>
	 * If the number < 1, set the number = 1.
	 * @param c
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <K, V>List<Map<K, V>> splitMapBySize(Map<K, V> c, int size) {
		if (c == null || c.size() == 0) {
			return Collections.EMPTY_LIST;
		} else if (size < 1) {
			List<Map<K, V>> arr = new ArrayList<Map<K, V>>();
			arr.add(c);
			return arr;
		} 
		
		int n = 1;
		List<Map<K, V>> returnList = new ArrayList<Map<K, V>>();
		Map<K, V> map = new HashMap<K, V>(size);
		
		for(Entry<K, V> entry : c.entrySet()) {
			map.put(entry.getKey(), entry.getValue());
			if (n % size == 0) {
				Map<K, V> tempMap = map;
				map = null;
				returnList.add(tempMap);
				map = new HashMap<K, V>(size);
			}
			++n;
		}
		
		if (c.size() % size != 0) {
			returnList.add(map);
		}
		
		return returnList;
	}

	public static <T> List<T> wipeRepeatList(List<T> list) {
		if(list == null)
			return null;
		
		Set<T> set = new HashSet<T>(list);
		return new ArrayList<T>(set);
	}
}
